package com.itasura.redisson.service;

import org.redisson.api.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 * @author sailor wang
 * @date 2018/11/26 5:12 PM
 * @description
 */
@Service
public class RedissonService {
    @Autowired
    private RedissonClient redissonClient;

    /**
     * 通用对象桶（Object Bucket）
     * Redisson的分布式RBucketJava对象是一种通用对象桶可以用来存放任类型的对象
     * <br/>
     * <p>
     * RBucket<AnyObject> bucket = redisson.getBucket("anyObject");
     * bucket.set(new AnyObject(1));
     * AnyObject obj = bucket.get();
     * <p>
     * bucket.trySet(new AnyObject(3));
     * bucket.compareAndSet(new AnyObject(4), new AnyObject(5));
     * bucket.getAndSet(new AnyObject(6));
     *
     * @param objectName
     * @return
     */
    public <T> RBucket<T> getRBucket(String objectName) {
        RBucket<T> bucket = redissonClient.getBucket(objectName);
        return bucket;
    }

    /**
     * Redisson的分布式RBinaryStream Java对象同时提供了InputStream接口和OutputStream接口的实现。
     * 流的最大容量受Redis主节点的内存大小限制。
     * <br/>
     * RBinaryStream stream = redisson.getBinaryStream("anyStream");
     * byte[] content = ...
     * stream.set(content);
     * <p>
     * InputStream is = stream.getInputStream();
     * byte[] readBuffer = new byte[512];
     * is.read(readBuffer);
     * <p>
     * OutputStream os = stream.getOuputStream();
     * byte[] contentToWrite = ...
     * os.write(contentToWrite);
     *
     * @param objectName
     * @return
     */
    public RBinaryStream getBinaryStream(String objectName) {
        RBinaryStream stream = redissonClient.getBinaryStream(objectName);
        return stream;
    }

    /**
     * Redisson的分布式RGeoJava对象是一种专门用来储存与地理位置有关的对象桶。
     * <br/>
     * <p>
     * RGeo<String> geo = redisson.getGeo("test");
     * geo.add(new GeoEntry(13.361389, 38.115556, "Palermo"),
     * new GeoEntry(15.087269, 37.502669, "Catania"));
     * geo.addAsync(37.618423, 55.751244, "Moscow");
     * <p>
     * Double distance = geo.dist("Palermo", "Catania", GeoUnit.METERS);
     * geo.hashAsync("Palermo", "Catania");
     * Map<String, GeoPosition> positions = geo.pos("test2", "Palermo", "test3", "Catania", "test1");
     * List<String> cities = geo.radius(15, 37, 200, GeoUnit.KILOMETERS);
     * Map<String, GeoPosition> citiesWithPositions = geo.radiusWithPosition(15, 37, 200, GeoUnit.KILOMETERS);
     *
     * @param objectName
     * @param <T>
     * @return
     */
    public <T> RGeo<T> getGeo(String objectName) {
        RGeo<T> rGeo = redissonClient.getGeo(objectName);
        return rGeo;
    }

    /**
     * Redisson的分布式RBitSetJava对象采用了与java.util.BiteSet类似结构的设计风格。
     * 可以理解为它是一个分布式的可伸缩式位向量。需要注意的是RBitSet的大小受Redis限制，最大长度为4 294 967 295。
     * <br/>
     * RBitSet set = redisson.getBitSet("simpleBitset");
     * set.set(0, true);
     * set.set(1812, false);
     * set.clear(0);
     * set.addAsync("e");
     * set.xor("anotherBitset");
     *
     * @param objectName
     * @return
     */
    public RBitSet getBitSet(String objectName) {
        RBitSet rBitSet = redissonClient.getBitSet(objectName);
        return rBitSet;
    }

    /**
     * 基于Redis的Redisson的分布式映射结构的RMap Java对象实现了java.util.concurrent.ConcurrentMap接口和java.util.Map接口。
     * 同时还保持了元素的插入顺序。该对象的最大容量受Redis限制，最大元素数量是4 294 967 295个。
     * <p>
     * 在特定的场景下，映射缓存（Map）上的高度频繁的读取操作，使网络通信都被视为瓶颈时，可以使用Redisson提供的带有本地缓存功能的映射。
     *
     * @param objectName
     * @return
     */
    public <K, V> RMap<K, V> getRMap(String objectName) {
        RMap<K, V> map = redissonClient.getMap(objectName);
        return map;
    }

    /**
     * LRU有界映射
     * Redisson提供了基于Redis的以LRU为驱逐策略的分布式LRU有界映射对象。顾名思义，
     * 分布式LRU有界映射允许通过对其中元素按使用时间排序处理的方式，主动移除超过规定容量限制的元素。
     * <br/>
     * RMapCache<String, String> map = redisson.getMapCache("map");
     * // 尝试将该映射的最大容量限制设定为10
     * map.trySetMaxSize(10);
     * <p>
     * // 将该映射的最大容量限制设定或更改为10
     * map.setMaxSize(10);
     * <p>
     * map.put("1", "2");
     * map.put("3", "3", 1, TimeUnit.SECONDS);
     *
     * @param objectName
     * @param <K>
     * @param <V>
     * @return
     */
    public <K, V> RMapCache<K, V> getMapCache(String objectName) {
        RMapCache<K, V> rMapCache = redissonClient.getMapCache(objectName);
        return rMapCache;
    }

    /**
     * 有序集（SortedSet）
     * 基于Redis的Redisson的分布式RSortedSet Java对象实现了java.util.SortedSet接口。在保证元素唯一性的前提下，通过比较器（Comparator）接口实现了对元素的排序。
     * <br/>
     * RSortedSet<Integer> set = redisson.getSortedSet("anySet");
     * set.trySetComparator(new MyComparator()); // 配置元素比较器
     * set.add(3);
     * set.add(1);
     * set.add(2);
     * <p>
     * set.removeAsync(0);
     * set.addAsync(5);
     *
     * @param objectName
     * @return
     */
    public <V> RSortedSet<V> getRSortedSet(String objectName) {
        RSortedSet<V> sortedSet = redissonClient.getSortedSet(objectName);
        return sortedSet;
    }

    /**
     * 获取集合
     * 基于Redis的Redisson的分布式Set结构的RSet Java对象实现了java.util.Set接口。通过元素的相互状态比较保证了每个元素的唯一性。
     * 该对象的最大容量受Redis限制，最大元素数量是4 294 967 295个。
     * <br/>
     * RSet<SomeObject> set = redisson.getSet("anySet");
     * set.add(new SomeObject());
     * set.remove(new SomeObject());
     *
     * @param objectName
     * @return
     */
    public <V> RSet<V> getRSet(String objectName) {
        RSet<V> rSet = redissonClient.getSet(objectName);
        return rSet;
    }

    /**
     * 获取列表
     * 基于Redis的Redisson分布式列表（List）结构的RList Java对象在实现了java.util.List接口的同时，确保了元素插入时的顺序。
     * 该对象的最大容量受Redis限制，最大元素数量是4 294 967 295个。
     * <p>
     * RList<SomeObject> list = redisson.getList("anyList");
     * list.add(new SomeObject());
     * list.get(0);
     * list.remove(new SomeObject());
     *
     * @param objectName
     * @return
     */
    public <V> RList<V> getRList(String objectName) {
        RList<V> rList = redissonClient.getList(objectName);
        return rList;
    }

    /**
     * 获取队列
     * 基于Redis的Redisson分布式无界队列（Queue）结构的RQueue Java对象实现了java.util.Queue接口。
     * 尽管RQueue对象无初始大小（边界）限制，但对象的最大容量受Redis限制，最大元素数量是4 294 967 295个。
     *
     * @param objectName
     * @return
     */
    public <V> RQueue<V> getRQueue(String objectName) {
        RQueue<V> rQueue = redissonClient.getQueue(objectName);
        return rQueue;
    }

    /**
     * 双端队列（Deque）
     * 基于Redis的Redisson分布式无界双端队列（Deque）结构的RDeque Java对象实现了java.util.Deque接口。
     * 尽管RDeque对象无初始大小（边界）限制，但对象的最大容量受Redis限制，最大元素数量是4 294 967 295个。
     * <p>
     * RDeque<SomeObject> queue = redisson.getDeque("anyDeque");
     * queue.addFirst(new SomeObject());
     * queue.addLast(new SomeObject());
     * SomeObject obj = queue.removeFirst();
     * SomeObject someObj = queue.removeLast();
     *
     * @param objectName
     * @return
     */
    public <V> RDeque<V> getRDeque(String objectName) {
        RDeque<V> rDeque = redissonClient.getDeque(objectName);
        return rDeque;
    }


    /**
     * 获取锁
     * 大家都知道，如果负责储存这个分布式锁的Redis节点宕机以后，而且这个锁正好处于锁住的状态时，这个锁会出现锁死的状态。
     * 为了避免这种情况的发生，Redisson内部提供了一个监控锁的看门狗，它的作用是在Redisson实例被关闭前，不断的延长锁的有效期。
     * 默认情况下，看门狗的检查锁的超时时间是30秒钟，也可以通过修改Config.lockWatchdogTimeout来另行指定。
     * <p>
     * 另外Redisson还通过加锁的方法提供了leaseTime的参数来指定加锁的时间。超过这个时间后锁便自动解开了。
     * <p>
     * // 加锁以后10秒钟自动解锁
     * // 无需调用unlock方法手动解锁
     * lock.lock(10, TimeUnit.SECONDS);
     * <p>
     * // 尝试加锁，最多等待100秒，上锁以后10秒自动解锁
     * boolean res = lock.tryLock(100, 10, TimeUnit.SECONDS);
     * ...
     * lock.unlock();
     * Redisson同时还为分布式锁提供了异步执行的相关方法：
     * <p>
     * RLock lock = redisson.getLock("anyLock");
     * lock.lockAsync();
     * lock.lockAsync(10, TimeUnit.SECONDS);
     * Future<Boolean> res = lock.tryLockAsync(100, 10, TimeUnit.SECONDS);
     * RLock对象完全符合Java的Lock规范。也就是说只有拥有锁的进程才能解锁，其他进程解锁则会抛出IllegalMonitorStateException错误。
     * 但是如果遇到需要其他进程也能解锁的情况，请使用分布式信号量Semaphore 对象.
     *
     * @param objectName
     * @return
     */
    public RLock getRLock(String objectName) {
        RLock rLock = redissonClient.getLock(objectName);
        return rLock;
    }

    /**
     * 获取读取锁
     * 基于Redis的Redisson分布式可重入读写锁RReadWriteLock
     * Java对象实现了java.util.concurrent.locks.ReadWriteLock接口。
     * 同时还支持自动过期解锁。该对象允许同时有多个读取锁，但是最多只能有一个写入锁。
     * <br/>
     * <p>
     * RReadWriteLock rwlock = redisson.getLock("anyRWLock");
     * // 最常见的使用方法
     * rwlock.readLock().lock();
     * // 或
     * rwlock.writeLock().lock();
     * 大家都知道，如果负责储存这个分布式锁的Redis节点宕机以后，而且这个锁正好处于锁住的状态时，这个锁会出现锁死的状态。
     * 为了避免这种情况的发生，Redisson内部提供了一个监控锁的看门狗，它的作用是在Redisson实例被关闭前，不断的延长锁的有效期。
     * 默认情况下，看门狗的检查锁的超时时间是30秒钟，也可以通过修改Config.lockWatchdogTimeout来另行指定。
     * <p>
     * 另外Redisson还通过加锁的方法提供了leaseTime的参数来指定加锁的时间。超过这个时间后锁便自动解开了。
     * <p>
     * // 10秒钟以后自动解锁
     * // 无需调用unlock方法手动解锁
     * rwlock.readLock().lock(10, TimeUnit.SECONDS);
     * // 或
     * rwlock.writeLock().lock(10, TimeUnit.SECONDS);
     * <p>
     * // 尝试加锁，最多等待100秒，上锁以后10秒自动解锁
     * boolean res = rwlock.readLock().tryLock(100, 10, TimeUnit.SECONDS);
     * // 或
     * boolean res = rwlock.writeLock().tryLock(100, 10, TimeUnit.SECONDS);
     * ...
     * lock.unlock();
     *
     * @param objectName
     * @return
     */
    public RReadWriteLock getRWLock(String objectName) {
        RReadWriteLock rwlock = redissonClient.getReadWriteLock(objectName);
        return rwlock;
    }

    /**
     * 获取原子数
     * Redisson的分布式整长形RAtomicLong对象和Java中的java.util.concurrent.atomic.AtomicLong对象类似
     * <br/>
     * RAtomicLong atomicLong = redisson.getAtomicLong("myAtomicLong");
     * atomicLong.set(3);
     * atomicLong.incrementAndGet();
     * atomicLong.get();
     *
     * @param objectName
     * @return
     */
    public RAtomicLong getRAtomicLong(String objectName) {
        RAtomicLong rAtomicLong = redissonClient.getAtomicLong(objectName);
        return rAtomicLong;
    }

    /**
     * 闭锁（CountDownLatch）
     * 基于Redisson的Redisson分布式闭锁（CountDownLatch）
     * Java对象RCountDownLatch采用了与java.util.concurrent.CountDownLatch相似的接口和用法。
     * <br/>
     * RCountDownLatch latch = redisson.getCountDownLatch("anyCountDownLatch");
     * latch.trySetCount(1);
     * latch.await();
     * <p>
     * // 在其他线程或其他JVM里
     * RCountDownLatch latch = redisson.getCountDownLatch("anyCountDownLatch");
     * latch.countDown();
     *
     * @param objectName
     * @return
     */
    public RCountDownLatch getRCountDownLatch(String objectName) {
        RCountDownLatch rCountDownLatch = redissonClient.getCountDownLatch(objectName);
        return rCountDownLatch;
    }

    /**
     * 消息主题（订阅分发）
     * RTopic<SomeObject> topic = redisson.getTopic("anyTopic");
     * topic.addListener(new MessageListener<SomeObject>() {
     *
     * @param objectName
     * @return
     * @Override public void onMessage(String channel, SomeObject message) {
     * //...
     * }
     * });
     * <p>
     * // 在其他线程或JVM节点
     * RTopic<SomeObject> topic = redisson.getTopic("anyTopic");
     * long clientsReceivedMessage = topic.publish(new SomeObject());
     */
    public <M> RTopic<M> getRTopic(String objectName) {
        RTopic<M> rTopic = redissonClient.getTopic(objectName);
        return rTopic;
    }

    /**
     * 基于Redis的分布式限流器可以用来在分布式环境下现在请求方的调用频率。
     * 既适用于不同Redisson实例下的多线程限流，也适用于相同Redisson实例下的多线程限流。该算法不保证公平性。
     * <br/>
     * <p>
     * RRateLimiter rateLimiter = redisson.getRateLimiter("myRateLimiter");
     * // 初始化
     * // 最大流速 = 每1秒钟产生10个令牌
     * rateLimiter.trySetRate(RateType.OVERALL, 10, 1, RateIntervalUnit.SECONDS);
     * <p>
     * // 获取4个令牌
     * rateLimiter.tryAcquire(4);
     * <p>
     * // 尝试获取4个令牌，尝试等待时间为2秒钟
     * rateLimiter.tryAcquire(4, 2, TimeUnit.SECONDS);
     * <p>
     * rateLimiter.tryAcquireAsync(2, 2, TimeUnit.SECONDS);
     * <p>
     * // 尝试获取1个令牌，等待时间不限
     * rateLimiter.acquire();
     * <p>
     * // 尝试获取1个令牌，等待时间不限
     * RFuture<Void> future = rateLimiter.acquireAsync();
     *
     * @param objectName
     * @return
     */
    public RRateLimiter getRateLimiter(String objectName) {
        RRateLimiter rateLimiter = redissonClient.getRateLimiter(objectName);
        return rateLimiter;
    }

    /**
     * 布隆过滤器（Bloom Filter）
     * Redisson利用Redis实现了Java分布式布隆过滤器（Bloom Filter）。所含最大比特数量为2^32。
     * <br/>
     * RBloomFilter<SomeObject> bloomFilter = redisson.getBloomFilter("sample");
     * // 初始化布隆过滤器，预计统计元素数量为55000000，期望误差率为0.03
     * bloomFilter.tryInit(55000000L, 0.03);
     * bloomFilter.add(new SomeObject("field1Value", "field2Value"));
     * bloomFilter.add(new SomeObject("field5Value", "field8Value"));
     * bloomFilter.contains(new SomeObject("field1Value", "field8Value"));
     *
     * @param objectName
     * @param <T>
     * @return
     */
    public <T> RBloomFilter<T> getBloomFilter(String objectName) {
        RBloomFilter<T> bloomFilter = redissonClient.getBloomFilter(objectName);
        return bloomFilter;
    }

    /**
     * 阻塞队列（Blocking Queue）
     * 基于Redis的Redisson分布式无界阻塞队列（Blocking Queue）结构的RBlockingQueue
     * Java对象实现了java.util.concurrent.BlockingQueue接口。尽管RBlockingQueue对象无初始大小（边界）限制，但对象的最大容量受Redis限制，
     * 最大元素数量是4 294 967 295个。
     * <br/>
     * RBlockingQueue<SomeObject> queue = redisson.getBlockingQueue("anyQueue");
     * queue.offer(new SomeObject());
     * <p>
     * SomeObject obj = queue.peek();
     * SomeObject someObj = queue.poll();
     * SomeObject ob = queue.poll(10, TimeUnit.MINUTES);
     *
     * @param objectName
     * @param <T>
     * @return
     */
    public <T> RBlockingQueue<T> getBlockingQueue(String objectName) {
        return redissonClient.getBlockingQueue(objectName);
    }

    /**
     * 延迟队列（Delayed Queue）
     * 基于Redis的Redisson分布式延迟队列（Delayed Queue）结构的RDelayedQueue
     * Java对象在实现了RQueue接口的基础上提供了向队列按要求延迟添加项目的功能。该功能可以用来实现消息传送延迟按几何增长或几何衰减的发送策略。
     * <br/>
     * RQueue<String> distinationQueue = ...
     * RDelayedQueue<String> delayedQueue = getDelayedQueue(distinationQueue);
     * // 10秒钟以后将消息发送到指定队列
     * delayedQueue.offer("msg1", 10, TimeUnit.SECONDS);
     * // 一分钟以后将消息发送到指定队列
     * delayedQueue.offer("msg2", 1, TimeUnit.MINUTES);
     * 在该对象不再需要的情况下，应该主动销毁。仅在相关的Redisson对象也需要关闭的时候可以不用主动销毁。
     * <p>
     * RDelayedQueue<String> delayedQueue = ...
     * delayedQueue.destroy();
     *
     * @param objectName
     * @param <T>
     * @return
     */
    public <T> RDelayedQueue<T> getDelayedQueue(String objectName) {
        RDelayedQueue<T> delayedQueue = redissonClient.getDelayedQueue(getRQueue(objectName));
        return delayedQueue;
    }
}